package com.ddd.filter;

import com.ddd.utils.FilterUtil;
import com.ddd.utils.UserTokenUtil;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by zhouxj6112 on 2019/12/13.
 */
@Slf4j
@Component
@ConfigurationProperties(prefix = "url-filter")
public class PreRequestFilter extends ZuulFilter {
    @Autowired
    private UserTokenUtil userTokenUtil;

    @Override
    public String filterType() {
        // 过滤器的类型
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        // 0
        // 过滤器级别 0最高
        return FilterConstants.SEND_ERROR_FILTER_ORDER;
    }

    @Override
    public boolean shouldFilter() {
        // 是否启用
        return true;
    }

    @Value("${url-filter.token-pass-url-list}")
    private List<String> token_pass_url_list;

    // 参考: https://blog.csdn.net/dunegao/article/details/90720241
    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        String url = request.getRequestURL().toString();
        boolean isPassUrl = FilterUtil.checkWhiteList(token_pass_url_list, url);

        // 获取认证
        String userToken = request.getHeader(HttpHeaders.AUTHORIZATION);

        if (userToken != null) {
            userToken = userToken.replace("token ", "");
        }

        log.info("================userToken, {}", userToken);
        if (userToken != null && userToken.length() > 0) {
            // 将userToken变成userId传到后面去
            Long userId = null;
            Map<String, List<String>> paras = new HashMap<>();
            try {
                // 根据userToken,反编译出userId
                userId = userTokenUtil.fetchUserId(userToken, paras);
                log.info("====================paras:{}, userId", paras, userId);
            } catch (Exception e) {
                log.error("token解析失败", e);
            }

            //这个请求最终不会被zuul转发到后端服务器,但是如果当前Filter后面还存在其他Filter,那么其他Filter仍然会被调用到
            if (userId == null && !isPassUrl) {
                ctx.setSendZuulResponse(false);
                ctx.getResponse().setContentType("application/json;charset=utf-8");
                ctx.setResponseBody("{\"code\":401,\"message\":\"登录信息已经过期\"}");
            } else {
                List list = new ArrayList<>();
                if (userId != null) {
                    list.add(userId.toString());
                    paras.put("userId", list);
                }
                Map<String, String[]> parameters = request.getParameterMap();
                if (parameters != null && parameters.size() > 0) {
                    for (String key : parameters.keySet()) {
                        String[] strings = parameters.get(key);
                        List arr = new ArrayList<>();
                        for (String str : strings) {
                            arr.add(str);
                        }
                        paras.put(key, arr);
                    }
                }
                ctx.setRequestQueryParams(paras);
                // 方便后面去取
                ctx.set("userId", userId);
            }
        } else if (!isPassUrl) {
            // 除了不需要登陆的几个接口外,其它都需要登陆
            ctx.setSendZuulResponse(false);
            ctx.getResponse().setContentType("application/json;charset=utf-8");
            ctx.setResponseBody("{\"code\":401,\"msg\":\"没有访问权限！\"}");
        }
//        }

        // 存储客户端发起请求的时间戳,方便后面记录接口在服务端的耗时
        ctx.set("startTime", System.currentTimeMillis());

        return null;
    }

}
